package com.dream.service.recommender.hub.rec;

import com.dream.common.model.response.BaseListResponse;
import com.dream.common.model.response.BaseResponse;
import com.dream.common.model.response.ErrorCode;
import com.dream.service.designer.api.app.DesignerAppService;
import com.dream.service.procure.domain.enums.StockStatus;
import com.dream.service.product.domain.entity.SpuBase;
import com.dream.service.recommender.hub.util.CacheUtil;
import com.dream.service.recommender.hub.util.ParamUtil;
import com.dream.service.recommender.toolkits.cache.RedisCache;
import com.dream.service.recommender.toolkits.utils.ConfigUtil;
import com.dream.service.recommender.toolkits.utils.StringUtils;
import com.dream.service.search.api.SearchRecallService;
import com.dream.service.search.domain.entity.ProductRecallResult;
import com.dream.service.search.domain.request.ProductSearchRequest;
import com.dream.service.wrapper.domain.entity.SPUData;
import com.dream.service.recommender.base.compare.WeightComparator;
import com.dream.service.recommender.base.impl.BaseRecommenderService;
import com.dream.service.recommender.domain.request.BaseRequest;
import com.dream.service.recommender.domain.request.FrontParam;
import com.dream.service.recommender.domain.response.RecommenderData;
import com.dream.service.recommender.domain.response.RecommenderItem;
import com.dream.service.recommender.domain.response.RecommenderSku;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

/**
 * 根据分类召回
 * Created by duxy on 2016/04/25.
 */
public class ProductDetailRecommender extends BaseRecommenderService {

    private Logger logger = Logger.getLogger(ProductDetailRecommender.class);


    private SearchRecallService searchRecallService;

    public SearchRecallService getSearchRecallService() {
        return searchRecallService;
    }

    @Autowired
    public void setSearchRecallService(SearchRecallService searchRecallService) {
        this.searchRecallService = searchRecallService;
    }


    public static DesignerAppService designerAppService;

    public DesignerAppService getDesignerAppService() {
        return designerAppService;
    }

    @Autowired
    public void setDesignerAppService(DesignerAppService designerAppService) {
        this.designerAppService = designerAppService;
    }

    // 获取商品数据倍数
    private int multiple = 5;

    // 失效时间间隔 (sec)
    private int residue_time_interval = Integer.parseInt(ConfigUtil.getPro("residue_time_interval_pd"));

    // 缓存
    private final String cacheKey = "rec_spudetail_list_";

    // 缓存
    private RedisCache redisCache = RedisCache.getInstance();

    @Override
    public BaseResponse<RecommenderData> getRecommender(BaseRequest<FrontParam> frontParamBaseRequest) {
        long sTime = System.currentTimeMillis();
        BaseResponse<RecommenderData> recommenderResponse = new BaseResponse<RecommenderData>();
        try {
            if (frontParamBaseRequest == null || frontParamBaseRequest.getParam() == null || frontParamBaseRequest.getParam().getUser() == null) {
                return buildResult(recommenderResponse, false, ErrorCode.PARAM_ERROR.getCode(), ErrorCode.PARAM_ERROR.getError_msg(), null);
            }
            FrontParam frontParam = frontParamBaseRequest.getParam();
            int cid = ParamUtil.getCid(frontParam);//前台分类id
            Integer cityId =  frontParam.getCityId();

//            System.out.println("ciiiiiiiiiiid:"+cid);
            int pagesize = ParamUtil.getPageSize(frontParam);
            Long spu = ParamUtil.getSpu(frontParam);
//            System.out.println(spu);
            logger.debug(spu);
            int page = ParamUtil.getPage(frontParam);
            Map<Integer, Double> categoryWeightMap = new HashMap<Integer, Double>();
            if (cid > 0) {
                categoryWeightMap.put(cid, 1d);
            }

            //System.out.println(spu);
            /*int skip = pagesize * (page - 1);*/
            //已经展示sku集合
            String pin = ParamUtil.getPin(frontParam);
            String uuid = ParamUtil.getUUid(frontParam);
//            System.out.println(uuid);
            Map<String, String> extraValues = ParamUtil.getExtraValues(frontParam);

//            System.out.println(extraValues);

            Integer designerId = extraValues == null ? -1 : Integer.parseInt(extraValues.get("designerId"));//设计师id

            //找到设计师的所有关联商品
            Set<Long> designerMappingSpus = new HashSet<Long>();
            if (designerId != null) {
                BaseListResponse baseListResponse = designerAppService.getSpusSet(designerId);
                designerMappingSpus = (Set<Long>) baseListResponse.getResult().getList();//设计师关联的所有商品
            }
//            System.out.println(JSONObject.toJSONString("设计师关联spu：" + designerMappingSpus));

            Set<Long> tmpSet = gatherExistSpuInfo(pin, uuid, cid, page, pagesize, spu);
            HashSet<Long> existSpus = new HashSet<Long>();
            if (!tmpSet.equals(Collections.emptySet())) {
                existSpus = (HashSet<Long>) tmpSet;
            }
//            Set<Long> existSpus=new HashSet<Long>();
            if (!spu.equals(-1L)) {
                existSpus.add(spu);
            }
            //System.out.println(JSONObject.toJSONString(existSpus));
            List<ProductRecallResult> recallResults = gatherSearchRecallData(null, null, pagesize * multiple, existSpus, 0);
//            System.out.println(recallResults.size());
            //System.out.println(recallResults.size());
            RecommenderData recommenderData = buildResult(recallResults, cid, designerMappingSpus, spu,cityId);//spu是existSpu
            recommenderResponse = buildResult(recommenderResponse, true, ErrorCode.OK.getCode(), "", recommenderData, 0, pagesize);

            Set<Long> spus = rebuildPositionInfo(recommenderResponse.getResult());
            backupExistSpuInfo(pin, uuid, spus, cid, spu);
            long usedTime = System.currentTimeMillis() - sTime;
            recommenderData.setLatency(usedTime);
            recommenderResponse.setLatency(usedTime);
            return recommenderResponse;
        } catch (Exception e) {
            logger.error("product detail===>getRecommender:::", e);
            return buildResult(recommenderResponse, false, ErrorCode.PROCESS_ERROR.getCode(), e.getMessage(), null);
        }
    }

    public void backupExistSpuInfo(String pin, String uuid, Set<Long> spus, int category, Long spu) {
        if (StringUtils.isEmpty(pin) && StringUtils.isEmpty(uuid)) return;
        String major_uid = StringUtils.isEmpty(pin) ? uuid : pin;
        String key = cacheKey.concat("_").concat(spu.toString()).concat("_").concat(String.valueOf(category));
        //System.out.println(key);
        List<Long> cache = CacheUtil.backupCache(redisCache, key, spus, residue_time_interval, -1);
        //System.out.println("Backup Exist Spu :" + (cache == null ? "" : Arrays.toString(cache.toArray())));
    }

    /**
     * 更新位置信息
     *
     * @param recommenderData
     * @return
     */
    public Set<Long> rebuildPositionInfo(RecommenderData recommenderData) {
        if (recommenderData == null || StringUtils.isEmpty(recommenderData.getList())) {
            return null;
        }
        List<RecommenderItem> items = recommenderData.getList();
        Set<Long> spus = new HashSet<Long>();
        int pos = 1;
        for (RecommenderItem recommenderItem : items) {
            recommenderItem.setPos(pos++);
            if (recommenderItem instanceof RecommenderSku) {
                try {
                    spus.add(((RecommenderSku) recommenderItem).getSpu());
                } catch (Exception e) {
                    logger.error("product detail===>rebuildPositionInfo:::", e);

                }
            }
        }
        return spus;
    }

    public Set<Long> gatherExistSpuInfo(String pin, String uuid, int category, int pageNum, int pageSize, Long spu) {
        if (StringUtils.isEmpty(pin) && StringUtils.isEmpty(uuid)) {
            return Collections.emptySet();
        }
        String major_uid = StringUtils.isEmpty(pin) ? uuid : pin;
        String key = cacheKey.concat("_").concat(spu.toString()).concat("_").concat(String.valueOf(category));
        //System.out.println("exist key:"+key);
        if (pageNum == 1) {
            redisCache.delKey(key.getBytes());
            return Collections.emptySet();
        }
        Set<Long> spus = CacheUtil.getExistSpus(redisCache, key, (pageNum - 1) * pageSize);
        if (spus == null) {
            return Collections.emptySet();
        }
        return spus;
    }


    protected List<ProductRecallResult> gatherSearchRecallData(Map<Integer, Double> categoryWeightMap, Map<Integer, Double> labelWeightMap, int limit, Set<Long> existSpus, int skip) {
        ProductSearchRequest request = new ProductSearchRequest();
        if (categoryWeightMap != null && !categoryWeightMap.isEmpty()) {
            request.setFrontCategoryWeightMap(categoryWeightMap);
        }
        if (labelWeightMap != null && !labelWeightMap.isEmpty()) {
            request.setLabelWeightMap(labelWeightMap);
        }
        request.setLimit(limit);
        request.setSkip(skip);
        if (existSpus != null && !existSpus.isEmpty()) {
            request.setExistKeys(existSpus);
        }
        try {
            if (searchRecallService == null) {
                return null;
            }
            BaseResponse<List<ProductRecallResult>> recallResponse = searchRecallService.productSearchRecall(request);

            if (recallResponse.isSuccess()) {
                return recallResponse.getResult();
            }
        } catch (Exception e) {
            logger.error("product detail===>gatherSearchRecallData:::", e);
        }
        return null;
    }

    /**
     * 封装商品信息
     *
     * @param recallResult
     * @param spuData
     * @return
     */
    protected RecommenderSku buildProduct(ProductRecallResult recallResult, SPUData spuData) {

        RecommenderSku recommenderSku = new RecommenderSku();
        if (spuData == null || spuData.getSpuBase() == null || spuData.getStockStatus() == StockStatus.NO || spuData.getSpuBase().getIsPutOn() == 0) {
            return null;
        }
        SpuBase spuBase = spuData.getSpuBase();
//        System.out.println(">>>" + spuBase.getSpu());
        recommenderSku.setSpu(spuBase.getSpu());
        recommenderSku.setSale_type(spuBase.getSale_type());
        recommenderSku.setMain_sku(spuBase.getMain_sku());
        recommenderSku.setMain_title(spuBase.getMain_title());
        recommenderSku.setW(0);
        if (recallResult !=null && recallResult.getOther_image_paths() != null) {
            recommenderSku.setImage_paths(recallResult.getOther_image_paths());
        }
//        recommenderSku.setW(recallResult.getQuality_score());
        recommenderSku.setCid3(spuBase.getCategory_id());
        if (spuBase.getFront_category_ids() != null && spuBase.getFront_category_ids().size() > 0)
            recommenderSku.setFront_category_id(spuBase.getFront_category_ids().get(0));//只取得一个，不知道会不会有问题

        if (!StringUtils.isEmpty(spuBase.getMain_image_url())) {
            recommenderSku.setMain_image_url(spuBase.getMain_image_url());
        } else {
            return null;
        }
        if (spuData.getSkuPrice() != null) {
            recommenderSku.setSkuPrice(spuData.getSkuPrice());
        } else {
            return null;
        }

        return recommenderSku;
    }

    /**
     * 封装结果
     *
     * @param recallResults
     * @param spu
     * @return
     */

    private int getIndexRecallResults(List<ProductRecallResult> recallResults, Long spu) {
        int i = 0;
        for (i = 0; i < recallResults.size(); i++) {
            if (recallResults.get(i).getSpu().longValue() == spu.longValue()) {
                return i;
            }
        }
        return -1;
    }

    private RecommenderData buildResult(List<ProductRecallResult> recallResults, int cid3, Set<Long> designerMappingSpus, Long existSpu,Integer cityId) {
        if (StringUtils.isEmpty(recallResults)) {
            return new RecommenderData();
        }
        RecommenderData<RecommenderSku> recommenderData = new RecommenderData<RecommenderSku>();
        List<RecommenderSku> recommenderSkus = new ArrayList<RecommenderSku>();
        recommenderData.setList(recommenderSkus);
        Set<Long> spus = new HashSet<Long>();
        for (ProductRecallResult recallResult : recallResults) {
            spus.add(recallResult.getSpu());
        }
        designerMappingSpus.remove(existSpu);
        spus.addAll(designerMappingSpus);

        Map<Long, SPUData> spuDataMap = getBaseInfo(spus,cityId);
//        System.out.println(JSONObject.toJSONString(spuDataMap));
        if (spuDataMap == null || spuDataMap.isEmpty()) {
            return recommenderData;
        }
        for (Long spu : spus) {
//            System.out.println("===" + spu);

            int n = getIndexRecallResults(recallResults, spu);
//            System.out.println(n);
            RecommenderSku recommenderSku = buildProduct(n == -1 ? null : recallResults.get(n), spuDataMap.get(spu));
            if (recommenderSku != null) {
                recommenderSkus.add(recommenderSku);
            }
        }
//        for (ProductRecallResult recallResult : recallResults) {
//            System.out.println("===" + recallResult.getSpu());
//            RecommenderSku recommenderSku = buildProduct(recallResult, spuDataMap.get(recallResult.getSpu()));
//            if (recommenderSku != null) {
//                recommenderSkus.add(recommenderSku);
//            }
//        }
        SortAndRankAtProductDetail(recommenderData, spuDataMap, cid3, designerMappingSpus);
        return recommenderData;
    }


    public RecommenderData SortAndRankAtProductDetail(RecommenderData recommenderData, Map<Long, SPUData> spuDataMap, int frontCid, Set<Long> designerMappingSpus) {
        if (recommenderData == null) {
            return recommenderData;
        }
        List<RecommenderSku> recommenderSkus = recommenderData.getList();
        if (StringUtils.isEmpty(recommenderSkus)) {
            return recommenderData;
        }
        List<RecommenderSku> desRecommenderSkusList = new ArrayList<RecommenderSku>();
        List<RecommenderSku> cid3RecommenderSkusList = new ArrayList<RecommenderSku>();
        List<RecommenderSku> otherRecommenderSkusList = new ArrayList<RecommenderSku>();
        List<RecommenderSku> subRecommenderItems = new ArrayList<RecommenderSku>();
        Map<Integer, List<RecommenderSku>> categoryItems = new HashMap<Integer, List<RecommenderSku>>();
        for (RecommenderSku recommenderSku : recommenderSkus) {//根据cid重组spu
            recommenderSku.setW(Math.random());
            long spu = recommenderSku.getSpu();
            SPUData spuData = spuDataMap.get(spu);
//            System.out.println(spu);
            if (spuData == null) {
                continue;
            }
            SpuBase spuBase = spuData.getSpuBase();
//            Syem.out.println(recommenderSku.getFront_category_id());
            if (designerMappingSpus.contains(recommenderSku.getSpu())) {
                recommenderSku.setW(2);//设计师商品权重为2
                desRecommenderSkusList.add(recommenderSku);
            } else if (recommenderSku.getFront_category_id() == frontCid) {
//                System.out.println(frontCid);
                recommenderSku.setW(1);
                cid3RecommenderSkusList.add(recommenderSku);

            } else {
                recommenderSku.setW(Math.random());
                otherRecommenderSkusList.add(recommenderSku);
            }
//            Collections.sort(desRecommenderSkusList, new WeightComparator());

//            Collections.sort(cid3RecommenderSkusList, new WeightComparator());
            Collections.sort(otherRecommenderSkusList, new WeightComparator());
//            List<RecommenderSku> relSkus = categoryItems.get(recommenderSku.getCid3());
//            if (relSkus == null) {
//                relSkus = new ArrayList<RecommenderSku>();
//                categoryItems.put(recommenderSku.getCid3(), relSkus);
//            }
//            relSkus.add(recommenderSku);
        }
        List<RecommenderSku> sortRecommenderItems = new ArrayList<RecommenderSku>();
//        boolean loop = true;
        sortRecommenderItems.addAll(desRecommenderSkusList);
        int cid3Num = cid3RecommenderSkusList.size() < 8 ? cid3RecommenderSkusList.size() : 8;
        int otherNum = otherRecommenderSkusList.size() < (20 - cid3Num) ? otherRecommenderSkusList.size() : (20 - cid3Num);
        for (int i = 0; i < cid3Num; i++) {
            sortRecommenderItems.add(cid3RecommenderSkusList.remove(0));
        }
        //System.out.println(sortRecommenderItems.size());
        for (int i = 0; i < otherNum; i++) {

            sortRecommenderItems.add(otherRecommenderSkusList.remove(0));
        }
        //System.out.println(sortRecommenderItems.size());

//        Collections.sort(sortRecommenderItems, new WeightComparator());
//        do {
//
//            Iterator<Map.Entry<Integer, List<RecommenderSku>>> entryiterator = categoryItems.entrySet().iterator();
//            Map.Entry<Integer, List<RecommenderSku>> productentry = null;
//            while (entryiterator.hasNext()) {
//                productentry = entryiterator.next();
//                List<RecommenderSku> productList = productentry.getValue();
//                if (StringUtils.isEmpty(productList)) {
//                    entryiterator.remove();
//                    continue;
//                }
//                RecommenderSku recommenderSku = productList.remove(0);
//                if (productentry.getKey() == cid3)
//                    cid3RecommenderSku.add(recommenderSku);
//                else
//                    otherRecommenderItems.add(recommenderSku);
//            }
//            if (productentry != null && productentry.getKey() == cid3)
//                Collections.sort(cid3RecommenderSku, new WeightComparator());//相同品类的重排序
//                sortRecommenderItems.addAll(cid3RecommenderSku);
//            else
//                Collections.sort(otherRecommenderItems, new WeightComparator());//非同品类的重排序

//            sortRecommenderItems.addAll(subRecommenderItems);


//            if (categoryItems.isEmpty()) {
//                loop = false;
//            }
//            if (categoryItems.size() == 1) {
//                Set<Integer> keys = categoryItems.keySet();
//                Iterator<Integer> keyiterator = keys.iterator();
//                while (keyiterator.hasNext()) {
//                    Integer catid = keyiterator.next();
//                    sortRecommenderItems.addAll(categoryItems.get(catid));
//                }
//                loop = false;
//            }
//        } while (loop);

        recommenderData.setList(sortRecommenderItems);
        return recommenderData;
    }


}
